﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Numerics;
using Fractalz.FractalModels;
using System.Threading;

namespace Fractalz.Render
{
	class RenderEngine
	{
		private Utilities.PriorityQueue<IRenderable> renderQueue;
		private Dictionary<IRenderable, Thread[]> threadDictionary;
		private int threadcount; 

		public RenderEngine()
		{
			renderQueue = new Utilities.PriorityQueue<IRenderable>();
			threadDictionary = new Dictionary<IRenderable, Thread[]>();
			threadcount = 0;
		}

		/// <summary>
		/// Starts rendering the given renderable.
		/// Only works if threads are available.
		/// </summary>
		/// <param name="renderable"></param>
		public void startRendering(IRenderable renderable, int numThreads)
		{
			// Add new entry to the threadDictionary for this job
			threadDictionary.Add(renderable, new Thread[numThreads]);
			// Grab a reference to the thread array for this job
			Thread[] currentThreads = threadDictionary[renderable];
			// For each of the 
			for (int x = 0; x < numThreads; x++)
			{
				currentThreads[x] = new Thread(renderable.render);
				currentThreads[x].Start(((Object)(new RenderArgs(x, numThreads))));
			}
			

		}

		/// <summary>
		/// Pauses the rendering process for the given renderable.
		/// Frees the threads that were being used.
		/// Rendering can be resumed after being paused.
		/// </summary>
		/// <param name="renderable"></param>
		public void pauseRendering(IRenderable renderable)
		{
			// Set renderable's threads to go to sleep
			renderable.Sleeping = true;
		}

		/// <summary>
		/// Resumes the rendering process for a paused renderable.
		/// Only works if threads are available.
		/// </summary>
		/// <param name="renderable"></param>
		public void resumeRendering(IRenderable renderable)
		{
			// If there are enough available threads to start this item
			if (availableThreads() >= AppSettings.THREADS_PER_ITEM)
			{
				// Set sleeping to false
				renderable.Sleeping = false;

				// Send an interrupt to each thread to actually wake it up
				foreach (Thread t in threadDictionary[renderable])
				{
					t.Interrupt();
				}
			}
		}

		/// <summary>
		/// Stops the rendering process of the given renderable.
		/// Rendering is NOT resumeable after stopping.
		/// </summary>
		/// <param name="renderable">Renderable to be rendered</param>
		public void stopRendering(IRenderable renderable)
		{
			// Abort all the threads for the renderable
			foreach (Thread t in threadDictionary[renderable])
			{
				t.Abort();
			}
		}

		/// <summary>
		/// Returns the number of currently available threads.
		/// </summary>
		/// <returns>The number of available threads.</returns>
		public int availableThreads()
		{
			return AppSettings.MAX_THREADCOUNT - threadcount;
		}
	}
}
